package com.fms.util;

import com.fms.constant.MessageConstant;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
public class CastUtils {
    public static <T> List<T> castList(Object value, Class<T> clazz) {
        List<T> resultList;
        if (value instanceof List<?> list) {
            resultList = new ArrayList<>();
            for (Object item : list) {
                if (clazz.isInstance(item)) {
                    resultList.add(clazz.cast(item));
                } else {
                    // 处理非 T 类型的情况
                    throw new RuntimeException("转换类型出现错误");
                }
            }
        } else {
            // 处理 obj 不是 List 类型的情况
            throw new RuntimeException("转换类型出现错误");
        }
        return resultList;
    }

    public static String castWeeksToString(List<Integer> weeklist){
        StringBuilder resultString=new StringBuilder();
        weeklist.forEach(weekday->resultString.append(weekday).append(","));
        return resultString.substring(0, resultString.toString().lastIndexOf(","));
    }

    public static List<Integer> castStringToWeeks(String weekString){
        String[] weekArray=weekString.split(",");
        List<Integer> weekList=new ArrayList<>();
        for(String week:weekArray){
            weekList.add(Integer.parseInt(week));
        }
        return weekList;
    }

    public static String castCron(LocalTime localTime, List<Integer> weekDays){
        List<Integer> coreList = weekDays.stream().map(week -> week>=7?1:(week+1)).toList();
        String cron="0 "+localTime.getMinute()+" " + localTime.getHour() + " " + "? * "+ castWeeksToString(coreList);
        log.info("cron:{}", cron);
        return cron;
    }

    public static LocalDate castDispatchDate(LocalDate localDate,List<Integer> weekDays){
        log.info("当前时间:{}", localDate);
        log.info("周期{}", weekDays);
        for(int j=0,i=localDate.getDayOfWeek().getValue();j<7;i=(i+1)%7,j++){
            log.info("时间:{}", localDate);
            log.info("i:{}", i);
            if(weekDays.contains(i)){
                localDate=localDate.plusDays(j);
                break;
            }
            log.info("时间:{}", localDate);
        }
        return localDate;
    }

    public static Map<String,LocalDateTime> castLocalDateTime(LocalDate date,LocalTime startTime,LocalTime inTime,LocalTime outTime){
        LocalDateTime inDateTime=LocalDateTime.of(date,inTime);
        LocalDateTime outDateTime=LocalDateTime.of(date,outTime);
        if(startTime.isAfter(inTime)){
            inDateTime=inDateTime.plusDays(1);
        }
        if(inTime.isAfter(outTime)){
            outDateTime=outDateTime.plusDays(1);
        }
        return Map.of(
                MessageConstant.STAR_DATE_TIME,LocalDateTime.of(date,startTime),
                MessageConstant.IN_DATE_TIME,inDateTime,
                MessageConstant.OUT_DATE_TIME,outDateTime
        );
    }

    /**
     * 用于计算两个经纬度坐标转换为直线距离
     * @param startLongitude 开始经度
     * @param startLatitude 开始纬度
     * @param shootStartLongitude 目标经度
     * @param shootStartLatitude 目标纬度
     * @return 直线距离（米）
     */
    public static double castLineDistance(double startLongitude, double startLatitude, double shootStartLongitude, double shootStartLatitude) {
        double R = 6371.393;
        double phi1 = Math.toRadians(startLatitude); //度为单位的角度转换为用弧度表示的近似相等的角度
        double phi2 = Math.toRadians(shootStartLatitude);
        double delta_phi = Math.toRadians(shootStartLatitude - startLatitude);//两个纬度之间的差值，并将其从度转换为弧度。
        double delta_lambda = Math.toRadians(shootStartLongitude - startLongitude);//两个经度之间的差值，并将其从度转换为弧度。
        double a = Math.sin(delta_phi / 2) * Math.sin(delta_phi / 2)
                + Math.cos(phi1) * Math.cos(phi2) * Math.sin(delta_lambda / 2) * Math.sin(delta_lambda / 2);//两个经纬度之间的方位角，单位为弧度
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));//两点之间大圆距离的一半
        double d = R * c;//大圆距离的一半乘以地球的半径，得到两点之间的大圆距离。
        return d*1000;//返回（米）
    }
}
